#include "libcomm.h"

class RefCounterMap : public ThreadLock
{
public:
	~RefCounterMap(){ Clear();}
	CommonDestructor* AddRef(CommonDestructor* ptr)
	{
		MYLIB_ASSERT_NOTNULL(ptr);
		ThreadLockGuard guard(this);
		PTRMAP::iterator itor = m_map.find(ptr);
		if(itor == m_map.end())
		{
			m_map[ptr] = 1;
		}
		else
		{
			++(itor->second);
		}
		return ptr;
	}

	int Release(CommonDestructor* ptr)
	{
		ThreadLockGuard guard(this);
		PTRMAP::iterator itor = m_map.find(ptr);
		if(itor == m_map.end())
			return -1;
		int count = --(itor->second);
		MYLIB_ASSERT(count>=0);
		if(0 == count)
		{
			itor->first->Delete();
			itor->first->Release();
			m_map.erase(itor);
		}
		return count;
	}

	int Count() 
	{
		ThreadLockGuard guard(this);
		int count = 0;
		for (PTRMAP::iterator itor = m_map.begin(); itor != m_map.end(); itor++)
		{
			count += itor->second;
		}
		return count;
	}

private:
	RefCounterMap(){}
	void Clear()
	{
		ThreadLockGuard guard(this);
		m_map.clear();
	}
private:
	friend class Singleton<RefCounterMap>;
	typedef std::map<CommonDestructor*,int> PTRMAP;
	ThreadLock m_lock;
	PTRMAP m_map;
};


////////////////////////////////////////////////////////////////////////// SharedPtrImp

#define LOCKEDREFCOUNTER	RefCounterMap* refcounter = Singleton<RefCounterMap>::Instance();\
							ThreadLockGuard guard(refcounter);

int SharedPtrImp::PtrInstanceCount()
{
	return Singleton<RefCounterMap>::Instance()->Count();
}

SharedPtrImp::SharedPtrImp(CommonDestructor* destructor)
	:m_destructor(NULL)
{
	if(NULL != destructor)
	{
		LOCKEDREFCOUNTER;
		m_destructor = refcounter->AddRef(destructor);
	}
}

SharedPtrImp::~SharedPtrImp()
{
	Release();
}

void SharedPtrImp::Release()
{
	LOCKEDREFCOUNTER;
	if(NULL != m_destructor)
	{
		int count = refcounter->Release(m_destructor);
		MYLIB_ASSERT(count>=0);
		m_destructor = NULL;
	}
}

SharedPtrImp::SharedPtrImp(const SharedPtrImp& rhs)
	:m_destructor(NULL)
{
	LOCKEDREFCOUNTER;
	if(NULL != rhs.m_destructor)
	{
		m_destructor = refcounter->AddRef(rhs.m_destructor);
	}
}

SharedPtrImp& SharedPtrImp::operator=(const SharedPtrImp& rhs)
{
	LOCKEDREFCOUNTER;
	if(m_destructor != rhs.m_destructor)
	{
		this->Release();
		if(NULL != rhs.m_destructor)
		{
			m_destructor = refcounter->AddRef(rhs.m_destructor);
		}
	}
	return *this;
}

void* SharedPtrImp::ptr() const
{
	LOCKEDREFCOUNTER;
	return ((NULL == m_destructor)?NULL:m_destructor->ptr());
}

////////////////////////////////////////////////////////////////////////// ScopedPtrImp

ScopedPtrImp::ScopedPtrImp(CommonDestructor* destructor):m_destructor(destructor)
{
	MYLIB_ASSERT_NOTNULL(m_destructor);
}

ScopedPtrImp::~ScopedPtrImp()
{
	Release();
}

void ScopedPtrImp::Release()
{
	if(NULL != m_destructor)
	{
		m_destructor->Delete();
		m_destructor->Release();
		m_destructor = NULL; 
	}
}

void* ScopedPtrImp::ptr() const
{
	return ((NULL == m_destructor)?NULL:m_destructor->ptr());
}

void* ScopedPtrImp::detach()
{
	void* ptr = NULL;
	if(NULL != m_destructor)
	{
		ptr = m_destructor->ptr(); 
		m_destructor->Release();
		m_destructor = NULL;  
	}
	return ptr;
}

void ScopedPtrImp::attach(CommonDestructor* destructor)
{
	if(m_destructor != destructor)
	{
		Release();
		m_destructor = destructor;
	}
}